//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using JetBrains.Annotations;
namespace LargoCommon.Music
{
///
/// Harmonic Motive.
///
[Serializable]
public sealed class RhythmicMotive
{
#region Fields
///
/// Element schema.
///
private string elementSchema;
///
/// Mean Mobility.
///
private float? meanMobility;
///
/// Mean Variance.
///
private float? meanVariance;
///
/// Unique identifier.
///
private string uniqueIdentifier;
///
/// Melodic Structures.
///
[NonSerialized]
private IEnumerable rhythmicStructures;
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public RhythmicMotive() {
this.RhythmicStructures = new List();
}
///
/// Initializes a new instance of the RhythmicMotive class.
///
/// Name of the motive.
/// Rhythmical structures.
public RhythmicMotive(string name, IEnumerable rhythmicStructures) //// RhythmicCore core,
: this() {
if (rhythmicStructures == null) {
return;
}
this.Name = name;
//// 2014/12 Time optimization ... int barNumber = 1;
foreach (var rstruct in rhythmicStructures) {
if (rstruct == null) {
continue;
}
//// 2014/12 Time optimization
//// rstruct.BarNumber = barNumber++;
this.AddStructure(rstruct); //// 1, RhythmicStructures.Count()
}
}
#endregion
#region Properties - Xml
/// Gets Xml representation.
/// Property description.
public XElement GetXElement {
get {
var xe = new XElement(
"Motive",
new XAttribute("Length", this.Length));
var xstructs = new XElement("Structures");
foreach (var rstruct in this.RhythmicStructures) {
var xstruct = rstruct.GetXElement;
xstructs.Add(xstruct);
}
xe.Add(xstructs);
return xe;
}
}
#endregion
#region Properties
///
/// Gets or sets the name.
///
///
/// Property description.
///
[UsedImplicitly]
public string Shortcut { get; set; } //// CA1044 (FxCop)
///
/// Gets or sets the full name.
///
///
/// The full name.
///
[UsedImplicitly]
public string Name { get; set; } //// CA1044 (FxCop)
///
/// Gets or sets the number.
///
///
/// Property description.
///
public int Number { get; set; }
///
/// Gets or sets the first bar number.
///
///
/// The first bar number.
///
public int FirstBarNumber { get; set; }
///
/// Gets or sets the occurrence.
///
///
/// The occurrence.
///
public int Occurrence { get; set; }
///
/// Gets or sets the rhythmic structures.
///
///
/// The rhythmic structures.
///
public IEnumerable RhythmicStructures {
get {
Contract.Ensures(Contract.Result>() != null);
if (this.rhythmicStructures == null) {
throw new InvalidOperationException("Rhythmic structures are null.");
}
return this.rhythmicStructures;
}
set => this.rhythmicStructures = value ?? throw new ArgumentException("Rhythmic structures cannot be empty.", nameof(value));
}
///
/// Gets the length.
///
/// Property description.
public int Length => ((List)this.RhythmicStructures).Count;
/// Gets list of all already defined tones.
/// Property description.
public string UniqueIdentifier {
get {
if (this.uniqueIdentifier != null) {
return this.uniqueIdentifier;
}
var ident = new StringBuilder();
var rhythmicMotiveStructureList = this.RhythmicStructures.ToList();
ident.Append(string.Format(CultureInfo.CurrentCulture, "#{0}#", rhythmicMotiveStructureList.Count));
//// ident.Append(rms.StructuralCode); //// .ToString(CultureInfo.CurrentCulture)//// ElementSchema, TRhythmicStructure.ElementSchema
//// ElementSchema, DecimalNumber, ms.StructuralCode
foreach (var b in from rms in rhythmicMotiveStructureList
where rms?.GetStructuralCode != null
from b in rms.GetStructuralCode
select b) {
ident.Append(b);
}
this.uniqueIdentifier = ident.ToString();
return this.uniqueIdentifier;
}
}
/// Gets list of all already defined tones.
/// Property description.
[UsedImplicitly]
public string ElementSchema {
get {
if (this.elementSchema != null) {
return this.elementSchema;
}
var elemSchema = new StringBuilder();
foreach (var rms in this.RhythmicStructures) {
elemSchema.Append(rms.ElementSchema.ToString(CultureInfo.CurrentCulture)); //// ElementSchema, TRhythmicStructure.ElementSchema
elemSchema.Append("/");
}
this.elementSchema = elemSchema.ToString();
return this.elementSchema;
}
}
#endregion
#region Physical properties
/// Gets list of all already defined tones.
/// Property description.
[UsedImplicitly]
public float MeanMobility {
get {
var cnt = this.RhythmicStructures.Count();
if (this.meanMobility != null || cnt <= 0) {
return this.meanMobility ?? 0;
}
var totalMobility = this.RhythmicStructures.Sum(rms => rms.RhythmicBehavior.Mobility);
this.meanMobility = totalMobility / cnt;
return (float)this.meanMobility;
}
}
/// Gets list of all already defined tones.
/// Property description.
[UsedImplicitly]
public float MeanVariance {
get {
var cnt = this.RhythmicStructures.Count();
if (this.meanVariance != null || cnt <= 0) {
return this.meanVariance ?? 0;
}
var totalVariance = this.RhythmicStructures.Sum(rms => rms.FormalBehavior.Variance);
this.meanVariance = totalVariance / cnt;
return (float)this.meanVariance;
}
}
#endregion
#region Static Factory methods
///
/// Simple RhythmicMotive.
///
/// Rhythmical structure.
/// Returns value.
[UsedImplicitly]
public static RhythmicMotive SimpleRhythmicMotive(RhythmicStructure rhythmicStruct) {
if (rhythmicStruct == null) {
return null;
}
var rm = new RhythmicMotive();
//// 2014/12 Time optimization
//// rhythmicStruct.BarNumber = 1;
rm.AddStructure(rhythmicStruct);
return rm;
}
///
/// Simple Rhythmic Motive.
///
/// Rhythmical order.
/// The structural code.
///
/// Returns value.
///
[UsedImplicitly]
public static RhythmicMotive SimpleRhythmicMotive(byte rhythmicOrder, string structuralCode) { //// bool rhythmical, int barNumber,
var rm = new RhythmicMotive();
var rs = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Structure, rhythmicOrder);
for (var ib = 0; ib < 4; ib++) {
//// 2014/12 Time optimization
//// rstruct.BarNumber = barNumber + ib
var rstruct = new RhythmicStructure(rs, structuralCode);
rm.AddStructure(rstruct);
}
return rm;
}
#endregion
#region Public methods
///
/// Converts to order.
///
/// The given system.
public void ConvertToSystem(RhythmicSystem givenSystem) {
var cnt = this.RhythmicStructures.Count();
if (cnt == 0) {
return;
}
var newStructures = this.RhythmicStructures.Select(s => s.ConvertToSystem(givenSystem)).ToList();
this.RhythmicStructures = newStructures;
}
/// Returns value of characteristic planned for given musical bar.
/// Number of musical bar.
/// Returns value.
public string RhythmicStructuralCodeForBar(int barNumber) {
var structure = this.RhythmicStructureInBarNumber(barNumber);
return structure?.GetStructuralCode;
}
///
/// Adds the structure.
///
/// The structure.
public void AddStructure(RhythmicStructure structure) {
((List)this.RhythmicStructures).Add(structure);
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
[UsedImplicitly]
public override string ToString() {
return this.Name;
}
#endregion
#region Private methods
///
/// Rhythmic structure in bar.
///
/// The bar number.
/// Returns value.
private RhythmicStructure RhythmicStructureInBarNumber(int barNumber) {
if (barNumber < 1) {
throw new ArgumentOutOfRangeException(nameof(barNumber), "value must be positive");
}
var cnt = this.RhythmicStructures.Count();
if (cnt == 0) {
return null;
//// throw new ArgumentException("No rhythmic motive structure!");
}
var idx = (barNumber - 1) % cnt;
var structure = this.RhythmicStructures.ElementAt(idx);
return structure;
}
#endregion
}
}